use std::{net::{TcpStream, SocketAddr, IpAddr, Ipv4Addr}, io::{prelude::*, ErrorKind}, error::Error, fs, process::{Command, exit}, thread, time::Duration};

mod config;
use config::Config;

// 配置文件路径
const CONFIG_PATH: &'static str = "./config";

fn main() -> Result<(), Box<dyn Error>> {
    let config = Config::new(CONFIG_PATH);
    
    println!("正在启动（当前版本：{}）", config.version);

    let mut con = None;
    for _ in 0..3 {
        println!("正在连接服务器");
        match TcpStream::connect_timeout(
            &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 31, 2, 2)), 8888),
            Duration::from_secs(1))
        {
            Ok(s) => {
                con = Some(s);
                break;
            },
            Err(e) => match e.kind() {
                ErrorKind::TimedOut | ErrorKind::AddrNotAvailable => {
                    println!("连接错误，大概率是服务器蓝屏了，也有可能是我们正在更新后端，我们会尽快解决。");
                    println!("正在重试...");
                    continue;
                }
                _ => {
                    println!("暂时无法处理的错误：{}", e);
                    thread::sleep(Duration::from_secs(5));
                    exit(1);
                }
            }
        }
    }

    let mut con = match con {
        Some(s) => {
            println!("连接成功");
            s
        },
        None => {
            println!("连接错误");
            thread::sleep(Duration::from_secs(5));
            exit(1);
        }
    };

    // client连接时server立刻发送一个版本信息
    con.write_all(config.version.as_bytes())?;

    // 获取最新版本
    let mut ver = [0; 16];
    con.read(&mut ver)?;

    let ver = String::from_utf8(
        ver.into_iter().filter(|i| *i != 0).collect()
    )?;

    // 如果版本号不一致，server会直接发送app.asar
    if config.version != ver {
        println!("The latest version is: {}", ver);
        println!("Updating ZVMS...");

        let mut asar = vec![];
        con.read_to_end(&mut asar)?;

        fs::write("./resources/app.asar", asar)?;
        config.write(&ver);

        println!("Updated.");
    }

    println!("Starting main process.");

    Command::new("zvms").spawn()?;

    Ok(())
}
